// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.

// Author: Shuo Chen (chenshuo at chenshuo dot com)

#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

#include <muduo/net/TimerQueue.h>

#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/Timer.h>
#include <muduo/net/TimerId.h>

#include <boost/bind.hpp>

#include <sys/timerfd.h>

namespace muduo
{
 namespace net
 {
  namespace detail
  {

   int createTimerfd()
   {
     int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
                                    TFD_NONBLOCK | TFD_CLOEXEC);
     if (timerfd < 0)
     {
       LOG_SYSFATAL << "Failed in timerfd_create";
     }
     return timerfd;
   }

   struct timespec howMuchTimeFromNow(Timestamp when)
   {
     int64_t microseconds = when.microSecondsSinceEpoch()
                            - Timestamp::now().microSecondsSinceEpoch();
     if (microseconds < 100)
     {
       microseconds = 100;
     }
     struct timespec ts;
     ts.tv_sec = static_cast<time_t>(
         microseconds / Timestamp::kMicroSecondsPerSecond);
     ts.tv_nsec = static_cast<long>(
         (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
     return ts;
   }

   void readTimerfd(int timerfd, Timestamp now)
   {
     uint64_t howmany;
     ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
     LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
     if (n != sizeof howmany)
     {
       LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
     }
   }

   void resetTimerfd(int timerfd, Timestamp expiration)
   {
     // wake up loop by timerfd_settime()
     struct itimerspec newValue;
     struct itimerspec oldValue;
     bzero(&newValue, sizeof newValue);
     bzero(&oldValue, sizeof oldValue);
     newValue.it_value = howMuchTimeFromNow(expiration);
     int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
     if (ret)
     {
       LOG_SYSERR << "timerfd_settime()";
     }
   }

  }
 }
}

using namespace muduo;
using namespace muduo::net;
using namespace muduo::net::detail;

TimerQueue::TimerQueue(EventLoop *loop)
    : loop_(loop),
      timerfd_(createTimerfd()),
      timerfdChannel_(loop, timerfd_),
      timers_(),
      callingExpiredTimers_(false)
{
  timerfdChannel_.setReadCallback(
      boost::bind(&TimerQueue::handleRead, this));
  // we are always reading the timerfd, we disarm it with timerfd_settime.
  timerfdChannel_.enableReading();
}

TimerQueue::~TimerQueue()
{
  timerfdChannel_.disableAll();
  timerfdChannel_.remove();
  ::close(timerfd_);
  // do not remove channel, since we're in EventLoop::dtor();
  for (TimerList::iterator it = timers_.begin();
       it != timers_.end(); ++it)
  {
    delete it->second;
  }
}

TimerId TimerQueue::addTimer(const TimerCallback &cb,
                             Timestamp when,
                             double interval)
{
  Timer *timer = new Timer(cb, when, interval);
  loop_->runInLoop(
      boost::bind(&TimerQueue::addTimerInLoop, this, timer));
  return TimerId(timer, timer->sequence());
}

#ifdef __GXX_EXPERIMENTAL_CXX0X__

TimerId TimerQueue::addTimer(TimerCallback &&cb,
                             Timestamp when,
                             double interval)
{
  Timer *timer = new Timer(std::move(cb), when, interval);
  loop_->runInLoop(
      boost::bind(&TimerQueue::addTimerInLoop, this, timer));
  return TimerId(timer, timer->sequence());
}

#endif

void TimerQueue::cancel(TimerId timerId)
{
  loop_->runInLoop(
      boost::bind(&TimerQueue::cancelInLoop, this, timerId));
}

void TimerQueue::addTimerInLoop(Timer *timer)
{
  loop_->assertInLoopThread();
  bool earliestChanged = insert(timer);//将timmer添加到当前的TimerQuene中
//如果当前加入的timmer到时时间比原先TimerQuene中的所有定时器到时时间都短，则需要更新timefd_
  if (earliestChanged)
  {
    resetTimerfd(timerfd_, timer->expiration());
  }
}

void TimerQueue::cancelInLoop(TimerId timerId)
{
  loop_->assertInLoopThread();
  assert(timers_.size() == activeTimers_.size());
  ActiveTimer timer(timerId.timer_, timerId.sequence_);
  ActiveTimerSet::iterator it = activeTimers_.find(timer);
  if (it != activeTimers_.end())
  {
    size_t n = timers_.erase(Entry(it->first->expiration(), it->first));
    assert(n == 1);
    (void) n;
    delete it->first; // FIXME: no delete please
    activeTimers_.erase(it);
  }
  else if (callingExpiredTimers_)
  {
    cancelingTimers_.insert(timer);
  }
  assert(timers_.size() == activeTimers_.size());
}

void TimerQueue::handleRead()
{
  loop_->assertInLoopThread();
  //得到当前的时间
  Timestamp now(Timestamp::now());
  readTimerfd(timerfd_, now);
  //获取在这个时间点到时的所有定时器，并把他们存储在expired数组中
  //同时这个函数也会把这些定时器从timers_中删除掉
  std::vector<Entry> expired = getExpired(now);
  //开始处理定时器事件
  callingExpiredTimers_ = true;
  cancelingTimers_.clear();
  // safe to callback outside critical section
  for (std::vector<Entry>::iterator it = expired.begin();
       it != expired.end(); ++it)
  {
    //一次调用每个定时器的run函数，run函数里面会调用相应定时器设置的回调函数。
    it->second->run();
  }
  callingExpiredTimers_ = false;
  //因为可能有些定时器需要在一定间隔内循环触发，这里会刷新一遍定时器队列
  reset(expired, now);
}

std::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now)
{
  assert(timers_.size() == activeTimers_.size());
  std::vector<Entry> expired;
  Entry sentry(now, reinterpret_cast<Timer *>(UINTPTR_MAX));
  TimerList::iterator end = timers_.lower_bound(sentry);
  assert(end == timers_.end() || now < end->first);
  std::copy(timers_.begin(), end, back_inserter(expired));
  timers_.erase(timers_.begin(), end);

  for (std::vector<Entry>::iterator it = expired.begin();
       it != expired.end(); ++it)
  {
    ActiveTimer timer(it->second, it->second->sequence());
    size_t n = activeTimers_.erase(timer);
    assert(n == 1);
    (void) n;
  }

  assert(timers_.size() == activeTimers_.size());
  return expired;
}

void TimerQueue::reset(const std::vector<Entry> &expired, Timestamp now)
{
  Timestamp nextExpire;

  for (std::vector<Entry>::const_iterator it = expired.begin();
       it != expired.end(); ++it)
  {
    ActiveTimer timer(it->second, it->second->sequence());
    //如果这个定时器是需要重复启动的，即internal>0
    if (it->second->repeat()
        && cancelingTimers_.find(timer) == cancelingTimers_.end())
    {
      it->second->restart(now);//则重启定时器，其实就是重新设置对应timer的到时时间：expiration_
      insert(it->second);//把定时器重新加到Timequene中
    }
    else
    {
      // FIXME move to a free list
      // 否则就将定时器删除掉，记住expired中的所有定时器已经移出timers_了
      delete it->second; // FIXME: no delete please
    }
  }
  //找到最近到时的定时器，并重新设置timefd
  if (!timers_.empty())
  {
    nextExpire = timers_.begin()->second->expiration();
  }

  if (nextExpire.valid())
  {
    resetTimerfd(timerfd_, nextExpire);
  }
}

bool TimerQueue::insert(Timer *timer)
{
  loop_->assertInLoopThread();
  assert(timers_.size() == activeTimers_.size());
  bool earliestChanged = false;
  Timestamp when = timer->expiration();
  TimerList::iterator it = timers_.begin();
  //如果当前的定时器二叉树times_为空 或 里面最邻近到时的定时器的到时时间比timer久，则设置earliestChanged
  if (it == timers_.end() || when < it->first)
  {
    earliestChanged = true;
  }
  {
    //将timer加入到timers中，timers是一个set，它里面的元素按大小顺序存放
    std::pair<TimerList::iterator, bool> result
        = timers_.insert(Entry(when, timer));
    assert(result.second);
    (void) result;
  }
  {
    //将timer加入到ActiveTimerset中
    std::pair<ActiveTimerSet::iterator, bool> result
        = activeTimers_.insert(ActiveTimer(timer, timer->sequence()));
    assert(result.second);
    (void) result;
  }

  assert(timers_.size() == activeTimers_.size());
  //如果新加入的timer到时时间最近，则earliestChanged为true，反则为false
  return earliestChanged;
}

